%==========================================================================
% LMJ_SHELL.m
%
% This controls loading for most programs to be run
% It also provides an initial call to the model
% Following variables must be in memory
%
% cucd                   % Current Working directory
% onscreen=1;            % Will query to continue
% flag_makelocalcopy =1; % Copy the settings and loading file to the location.savePath
% root ='orig';          % Folder
% spec ='log';           %    SubFolder
% subf ='april 2010 pr1';%        Subfolder
% set_fname=[];          % Name of settings file, default is settings
% add2outpath=[];        % Append to LOADPATH name before the current date
%
% Subfunctions used:
% 
% LOAD_LMJFILES
%
%
% Created      : April 6 2010
% Last modified:
% June 2010    Allow for Missing data provided flag_mixfreq and flag_gtv
%               defined
%
% August 2014  Cleaned up and listed correct subfunctions used
%
% TO DO 12/27/2011
% Remove flag_GTV

% =========================================================================
cucd=pwd;



%% 1. If flags.mixFreq==1 add Harvey cummulator
if flags.mixedFreq==1
    disp('Insert Here Harvey Cummulator')
end

%% 2. model.handle Create model handle
model.handle=str2func(['mod',location.root,location.specification]);


%% 3. Load from priorStru.fileName
% Notify user of filename and location of Prior .
fprintf('\nLoading from file: %s\nDirectory: %s\n',priorStru.fileName,location.loadPath)

%==========================================================================
% Load prior for parameters
if isempty(priorStru.priorSheet)==true
    error('Not Loading a Prior');
end
fprintf('Loading prior from sheet: %s\n',priorStru.priorSheet)
cd(location.loadPath);

% Depending on whether or not the user has Unix, we can use xlsread or
% textread to load the priors.
if flags.unix==0
    [prior_num,prior_text]=xlsread(priorStru.fileName,priorStru.priorSheet);
    if size(prior_text,2)~=2;
        error('Prior for parameters requires 2 columns with the name and the distribution')
    end
    if ~isequal( size(prior_num),[size(prior_text,1) 4])
        error('Prior for parameters requires 4 numeric columns')
    end
    parnames =prior_text(:,1);
    prpar.dist=prior_text(:,2);
    prpar.mean=prior_num(:, 1);
    prpar.std=prior_num(:, 2);
    prpar.lbnd=prior_num(:, 3);
    prpar.ubnd=prior_num(:, 4);
    clear prior_num prior_text;
else
    % Compatibility with Unix AJ 1/19/2012
    [parnames,prpar.dist,prpar.mean,prpar.std,prpar.lbnd,prpar.ubnd]=...
        textread([load_fname,'.txt'],'%q%q%f%f%f%f','delimiter','\t');
end

% Convert the prior sheet into the structure format needed for Estimation
[posStru.param.est,posStru.param.cal,parStru.cal,prpar.prior,prpar.alphap,prpar.betap]=...
    loadprior(prpar.dist,prpar.mean,prpar.std,prpar.lbnd,prpar.ubnd);

% Print the Means on Screen
printcell( strtrim([{'Parameter' 'Dist' 'Mean' 'Dispers' 'LB' 'UB'}; parnames(posStru.param.est) prpar.dist(posStru.param.est)  ...
    num2cprec( [prpar.mean(posStru.param.est) prpar.std(posStru.param.est) prpar.lbnd(posStru.param.est) prpar.ubnd(posStru.param.est)] ) ]) );
if ~isempty(posStru.param.cal)
    fprintf('\nCalibrated Parameters:')
    printcell( [parnames(posStru.param.cal) num2cprec(parStru.cal)]);
end

if flags.onscreen == 1
    quer('c');
end

fprintf('\nFinished Loading Prior for Paramaters');
prpar.transMat=cr_indmat(prpar.dist,prpar.mean,prpar.std,posStru.param.est,prpar.lbnd,prpar.ubnd,...
    prpar.alphap,prpar.betap,parnames);
disp('PARTRMAT is the transformation matrix of the parameters to use with CSMINWEL');

%==========================================================================
% Steady state Prior
flags.ssPrior=0;
if ~isempty(priorStru.ssSheet);    
    fprintf('\nLoading prior for the SS from: %s',priorStru.ssSheet);
    cd(location.loadpath);
    if isunix==0
        [prior_num,prior_text]=xlsread(priorStru.fileName,priorStru.ssSheet);
        if size(prior_text,2)~=2;
            error('Prior for parameters requires 2 columns with the name and the distribution')
        end
        if ~isequal( size(prior_num),[size(prior_text,1) 4])
            error('Prior for parameters requires 4 numeric columns')
        end
        prssnames=prior_text(:,1);
        prss.dist=prior_text(:,2);
        prss.mean=prior_num(:, 1);
        prss.std=prior_num(:, 2);
        prss.lbnd=prior_num(:, 3);
        prss.ubnd=prior_num(:,4 );        
        clear prior_num prior_text;
    else
        disp('Loading prior for SS in Unix ')
        fprintf('Looking for file %s%s.txt\n',priorStru.fileName,priorStru.ssSheet);
        % Compatibility with Unix AJ 1/19/2012
        [prssnames,prss.dist,prss.mean,prss.std,prss.lbnd,prss.ubnd]=...
            textread([priorStru.fileName,priorStru.ssSheet,'.txt'],'%q%q%f%f%f%f','delimiter','\t');
    end
    [~,ssposcal,~,prss.prior,prss.alphap,prss.betap]=...
        loadprior(prss.dist,prss.mean,prss.std,prss.lbnd,prss.ubnd);
    if ~isempty(ssposcal)
        error('SS values cannot be calibrated if they are not parameters')
    end
    clear ssposcal;    
    if flags.onscreen==1
        disp('Priors for the Steady State');
        disp('SS, Distribution, Mean , Dispersion , Lower Bound, Upper Bound');
        printcell( [prssnames prss.dist  ...
            num2cprec( [prss.mean prss.std prss.lbnd prss.ubnd] ) ] );
        quer('c');
    end
    if onscreen == 1
        quer('c');
    end
    
    disp('  ');
    disp('Finished Loading Prior for Steady State');
    
    flags.ssPrior=1;
else 
    prss=[]; 
end 

if priorStru.randomGridStart~=1 && priorStru.randomGridStart~=0
    error('priorStru.randomGridStart must be zero or 1')
end

%% Random grid
disp('Checking if loading starting values from RandomGrid...');
if priorStru.randomGridStart==1
    if isempty(priorStru.randomGridSheet)==true
        error('priorStru.randomGridStart==1 but priorStru.randomGridSheet is empty')
    end
    fprintf('Loading grid from : %s',priorStru.randomGridSheet);
    cd(location.loadPath);
    if isunix==0
        [pargrid,parnames3]=xlsread(priorStru.fileName,priorStru.randomGridSheet);
        if size(pargrid,2) ~=2
            disp('Grid must have two columns only');
            disp('Use STRVALS_SHEET if wish to define specific starting values')
            error('END')
        end
    else
        % Compatibility with Unix AJ 1/19/2012
        disp('Loading for priorStru.randomGridSheet in Unix ')
        fprintf('Looking for file %s%s.txt\n',priorStru.fileName,priorStru.randomGridSheet);
        [parnames3,tempVal1,tempVal2]=...
            textread([priorStru.fileName,priorStru.randomGridSheet,'.txt'],'%q%f','delimiter','\t');
        pargrid=[tempVal1 tempVal2];
        clear tempVal1 tempVal2
        if length(parnames)~=length(parnames3)
            error('Length of Parnames3 does not match parnames')
        end
        fprintf('Loaded %s%s.txt\n',priorStru.fileName,priorStru.randomGridSheet);
    end
    
    % Check first column is lower bound
    temp=find( pargrid(:,1) > pargrid(:,2) );
    if ~isempty( temp );
        disp('Left Column in PARGRID is greater than right column');
        printcell( [parnames3(temp) num2cprec(pargrid(temp,:))]);
        error('Left Column in PARGRID is greater than right column');
    end
    clear temp;
    
    disp('Names in Grid vs. Name Prior or calibrated value')
    printcell([parnames parnames3]);
    
    printcell([parnames3 num2cprec(pargrid)]);
    if flags.onscreen == 1
        quer('c');
    end
    disp('  ');
    disp('Finished Loading parameter, PARGRID');
    clear parnames3;
    priorStru.randomGridStart=1;
    paramToTest=prpar.mean;
    
end

if priorStru.randomGridStart==0
    disp('Random Grid turned off');
    if priorStru.randomPriorStart~=1 && priorStru.randomPriorStart~=0
        error('priorStru.randomPriorStart must be 0 or 1');
    end
end


if priorStru.randomPriorStart==1
    disp('Starting values drawn at random from prior');
    paramToTest=prpar.mean;
end
if priorStru.randomPriorStart==0 && priorStru.randomGridStart==0
    if isempty(priorStru.startSheet)==true
        error('priorStru.randomGridStart==0 and priorStru.randomPriorStart==0 but priorStru.startSheet is empty')
    end
    
    fprintf('Loading matrix of starting values from: %s\n',priorStru.startSheet);
    cd(location.loadPath);
    if isunix==0
        [parstrvals,parnames4]=xlsread(priorStru.fileName,priorStru.startSheet);
    else
        error('priorStru.startSheet not ready in Unix')
    end
    disp('Names in Starting values vs. Name')
    printcell([parnames parnames4]);
    
    printcell([parnames4 num2cprec(parstrvals)]);
    if flags.onscreen==1
        fprintf('Number of starting values loaded: %1.0f\n',size(parstrvals,2));
        quer('c');
    end
    
    disp('  ');
    disp('Finished Loading Starting Parameter Values , PARSTRVALS');
    paramToTest=parstrvals(:,1);
    %    flag_strvalsload=1;
end


if flags.ssPrior==1
    disp('Prior for steady state loaded');
end
if priorStru.randomGridStart==1
    disp('Loaded Lower and Upper Grid for starting values');
else
    disp('Loaded sheet with starting values');
end


%% 4. Create OUTPATH and make local copies of the file loaded and the
% settings file
if isfield(location,'add2SavePath')==false || isempty(location.add2SavePath)
    location.savePath=cr_dir(location.loadPath,strdate);
else
    location.savePath=cr_dir(location.loadPath,[location.add2SavePath,' ',strdate]);
end
fprintf('Created location.savePath: %s\n',location.savePath);

if flags.makeLocalCopy==1
    cd(location.loadPath);
    [flag_success,message] =copyfile([priorStru.fileName,'.xls'],location.savePath);
    if flag_success==1;
        fprintf('Copied %s to OUTPATH\n',priorStru.fileName);
    else
        disp(message);
        error('Cannot copy file loaded to OUTPATH');
    end
    [flag_success,message     ] =copyfile([location.settingsFile,'.m'],location.savePath);
    if flag_success==1;
        fprintf('Copied %s to OUTPATH\n',location.settingsFile);
    else
        disp(message);
        error('Cannot copy SET_FNAME to OUTPATH');
    end
    clear flag_sucess message;
end
cd(cucd);

%%
% -------------------------------------------------------------------------
% 5. Check Options for NL Solver exist, if not assign default values
% -------------------------------------------------------------------------
disp(' ');
if exist('solveopt','var')==0
    disp('Structure Options for NL solver not defined, assign default values');
    quer('c');
    solveopt=optimset('MaxFunEvals',200000,'Display','off',...
        'MaxIter',20000,'TolFun',1e-12);
else
    disp('Structure Options for NL solver exists');
end
fprintf('TolFun      = %3.10g\n',solveopt.TolFun);
fprintf('MaxFunEvals = %3.0f\n',solveopt.MaxFunEvals);
fprintf('MaxIter     = %3.0f\n',solveopt.MaxIter);
fprintf('Display     = %s\n',solveopt.Display);
if ~isempty( solveopt.TolX);
    fprintf('TolX        = %3.10g',solveopt.TolX);
end
if flags.onscreen==1
    quer('c');
end

%% 6. Initial call to the function handle with either:
% 1) Loaded starting value PARLOADVAL
% 2) First  in the matrix of starting values PARSTRVALS
% Obtain SSNAMES
numpar=length(paramToTest);

[GG, RR, CONS, eu, SDX, ZZ,~,ssvec,flag,ssnames,ny,nx,nz,stateNames,shockNamesStru]...
    =lmj_modfeval(model.handle,paramToTest,solveopt,addsol);
if ~isequal(eu,[1;1]);
    error('No Solution');
end
if flags.onscreen==1
    quer('c');
end

% =========================================================================
% Extracting position of SS parameters with prior
if flags.ssPrior~=0;
    display('extracting position of SS parameters with prior')
    ssposest=find(ismember(strtrim(ssnames),strtrim(prssnames)));
    printcell([ssnames(ssposest) num2cprec(ssvec(ssposest))]);
else
    display('Not loading PRIOR for SS');
    ssposest=[];
end

% =========================================================================
%% Check that if will change handles, models are identical and states exist
flags.changeHandle=false;
if isfield(model,'add2Handle')==true && ~isempty(model.add2Handle)
    flags.changeHandle=true;
    fprintf('Switching function handle from %s to %s\n',...
        func2str(model.handle),[func2str(model.handle),model.add2Handle]);
    disp(' ');
    disp('Verifying solutions match...');
    pause(0.25);
    [~,~,difvar,difc]=checkmodels_lmj(model.handle,...
        str2func([func2str(model.handle),model.add2Handle]),paramToTest,solveopt,addsol);
    if difvar < 1e-5;
        disp('Solutions identical')
    else
        disp('Solutions do not match')
    end
    if difc < 1e-5;
        disp('Constants identical');
    else
        disp('Constants do not match');
    end
    clear var1 var2 difvar difc
    [GG, RR, CONS, eu, SDX, ZZ, ~, ssvec, flag, ssnames,ny,nx,nz,stateNames,shockNamesStru]=...
        lmj_modfeval(str2func([func2str(model.handle),model.add2Handle]),paramToTest,solveopt,addsol);
end

disp(' ');
disp('End LMJ_SHELL');
disp('________________________'); 